home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1998 June / SGI Freeware 1998 June.iso / dist / fw_IZzip.idb / usr / freeware / src / zip / zipup.c.z / zipup.c
C/C++ Source or Header  |  1997-09-09  |  17KB  |  572 lines

  1. /*
  2.  
  3.  Copyright (C) 1990-1993 Mark Adler, Richard B. Wales, Jean-loup Gailly,
  4.  Kai Uwe Rommel and Igor Mandrichenko.
  5.  Permission is granted to any individual or institution to use, copy, or
  6.  redistribute this software so long as all of the original files are included,
  7.  that it is not sold for profit, and that this copyright notice is retained.
  8.  
  9. */
  10.  
  11. /*
  12.  *  zipup.c by Mark Adler and Jean-loup Gailly.
  13.  */
  14.  
  15. #define NOCPYRT         /* this is not a main module */
  16. #include <ctype.h>
  17. #include "zip.h"
  18. #include "revision.h"
  19. #include "crypt.h"
  20. #ifdef OS2
  21. #  include "os2zip.h"
  22. #endif
  23. #if defined(MMAP)
  24. #  include <sys/mman.h>
  25. #  ifdef SYSV
  26. #    include <sys/param.h>
  27. #  else
  28. #    define PAGESIZE getpagesize()
  29. #  endif
  30. #endif
  31.  
  32.  
  33. /* Use the raw functions for MSDOS and Unix to save on buffer space.
  34.    They're not used for VMS since it doesn't work (raw is weird on VMS).
  35.    (This sort of stuff belongs in fileio.c, but oh well.) */
  36. #ifdef VMS
  37. #  define fhow "r"
  38. #  define fbad NULL
  39.    typedef void *ftype;
  40. #  define zopen(n,p)   (vms_native?vms_open(n)    :(ftype)fopen((n),(p)))
  41. #  define zread(f,b,n) (vms_native?vms_read(f,b,n):fread((b),1,(n),(FILE*)(f)))
  42. #  define zclose(f)    (vms_native?vms_close(f)   :fclose((FILE*)(f)))
  43. #  define zerr(f)      (vms_native?vms_error(f)   :ferror((FILE*)(f)))
  44. #  define zstdin stdin
  45.    ftype vms_open OF((char *));
  46.    int vms_read OF((ftype, char *, int));
  47.    int vms_close OF((ftype));
  48.    int vms_error OF((ftype));
  49. #else /* !VMS */
  50. #  if (defined(MSDOS) && !defined(ATARI_ST)) || defined(__human68k__)
  51. #    include <io.h>
  52. #    include <fcntl.h>
  53. #    define fhow (O_RDONLY|O_BINARY)
  54. #  else /* !MSDOS */
  55. #    if defined(SYSV) || defined(__386BSD__)
  56. #      include <fcntl.h>  /* open(), read(), close(), lseek() */
  57. #    endif
  58. #    ifdef TOPS20
  59. #      define O_RDONLY (0)
  60. #      define O_UNCONVERTED     (0400) /* Forced NO conversion requested */
  61. #      define fhow (O_RDONLY | O_UNCONVERTED)
  62. #    else
  63. #      ifdef AMIGA
  64. #        include <fcntl.h>
  65. #        define fhow (O_RDONLY | O_RAW)
  66. #        define fbad (-1)
  67. #        ifdef AZTEC_C
  68. #          define O_RAW 0
  69. #        endif
  70. #      else
  71. #        define fhow 0
  72. #      endif
  73. #    endif
  74. #  endif /* ?MSDOS */
  75.    typedef int ftype;
  76. #  ifndef fbad
  77. #    define fbad (-1)
  78. #  endif
  79. #  define zopen(n,p) open(n,p)
  80. #  define zread(f,b,n) read(f,b,n)
  81. #  define zclose(f) close(f)
  82. #  define zerr(f) (k==(extent)(-1L))
  83. #  define zstdin 0
  84. #endif /* ?VMS */
  85.  
  86. #ifndef UTIL
  87.  
  88. #if defined(MMAP) || defined(BIG_MEM)
  89.   extern uch * window;          /* Used to read all input file at once */
  90. #endif
  91. extern ulg window_size;         /* size of said window */
  92.  
  93. /* Local data */
  94.  
  95.   local ulg crc;       /* crc on uncompressed file data */
  96.   local ftype ifile;   /* file to compress */
  97.   local long remain;
  98.   /* window bytes not yet processed. >= 0 only for BIG_MEM */
  99. #endif
  100. ulg isize;           /* input file size. global only for debugging */    
  101.  
  102. /* Local functions */
  103. #if defined(PROTO) && !defined(UTIL)
  104.    local int suffixes(char *, char *);
  105. #endif
  106.  
  107.  
  108. /* Note: a zip "entry" includes a local header (which includes the file
  109.    name), an encryption header if encrypting, the compressed data
  110.    and possibly an extended local header. */
  111.  
  112. int zipcopy(z, x, y)
  113. struct zlist far *z;    /* zip entry to copy */
  114. FILE *x, *y;            /* source and destination files */
  115. /* Copy the zip entry described by *z from file *x to file *y.  Return an
  116.    error code in the ZE_ class.  Also update tempzn by the number of bytes
  117.    copied. */
  118. {
  119.   ulg n;                /* holds local header offset */
  120.  
  121.   Trace((stderr, "zipcopy %s\n", z->zname));
  122.   n = 4 + LOCHEAD + (long)z->nam + (long)z->ext;
  123.  
  124.   if (fix > 1) {
  125.     /* do not trust the old compressed size */
  126.     if (putlocal(z, y) != ZE_OK)
  127.       return ZE_TEMP;
  128.  
  129.     if (fseek(x, z->off + n, SEEK_SET)) /* seek to compressed data */
  130.       return ferror(x) ? ZE_READ : ZE_EOF;
  131.  
  132.     z->off = tempzn;
  133.     tempzn += n;
  134.     n = z->siz;
  135.   } else {
  136.     if (fseek(x, z->off, SEEK_SET))     /* seek to local header */
  137.       return ferror(x) ? ZE_READ : ZE_EOF;
  138.  
  139.     z->off = tempzn;
  140.     n += z->siz;
  141.   }
  142.   /* copy the compressed data and the extended local header if there is one */
  143.   if (z->lflg & 8) n += 16;
  144.   tempzn += n;
  145.   return fcopy(x, y, n);
  146. }
  147.  
  148.  
  149. #ifndef UTIL
  150.  
  151. int percent(n, m)
  152. ulg n;
  153. ulg m;               /* n is the original size, m is the new size */
  154. /* Return the percentage compression from n to m using only integer
  155.    operations */
  156. {
  157.   if (n > 0xffffffL)            /* If n >= 16M */
  158.   {                             /*  then divide n and m by 256 */
  159.     n += 0x80;  n >>= 8;
  160.     m += 0x80;  m >>= 8;
  161.   }
  162.   return n > m ? (int)(1 + (200 * (n - m)/n)) / 2 : 0;
  163. }
  164.  
  165. local int suffixes(a, s)
  166. char *a;                /* name to check suffix of */
  167. char *s;                /* list of suffixes separated by : or ; */
  168. /* Return true if a ends in any of the suffixes in the list s. */
  169. {
  170.   int m;                /* true if suffix matches so far */
  171.   char *p;              /* pointer into special */
  172.   char *q;              /* pointer into name a */
  173.  
  174.   m = 1;
  175. #ifdef VMS
  176.   if( (q = strrchr(a,';')) != NULL )    /* Cut out VMS file version */
  177.     --q;
  178.   else
  179.     q = a + strlen(a) - 1;
  180. #else
  181.   q = a + strlen(a) - 1;
  182. #endif
  183.   for (p = s + strlen(s) - 1; p >= s; p--)
  184.     if (*p == ':' || *p == ';')
  185.       if (m)
  186.         return 1;
  187.       else
  188.       {
  189.         m = 1;
  190. #ifdef VMS
  191.         if( (q = strrchr(a,';')) != NULL )      /* Cut out VMS file version */
  192.           --q;
  193.         else
  194.           q = a + strlen(a) - 1;
  195. #else
  196.         q = a + strlen(a) - 1;
  197. #endif
  198.       }
  199.     else
  200.     {
  201.       m = m && q >= a && case_map(*p) == case_map(*q);
  202.       q--;
  203.     }
  204.   return m;
  205. }
  206.  
  207. int zipup(z, y)
  208. struct zlist far *z;    /* zip entry to compress */
  209. FILE *y;                /* output file */
  210. /* Compress the file z->name into the zip entry described by *z and write
  211.    it to the file *y. Encrypt if requested.  Return an error code in the
  212.    ZE_ class.  Also, update tempzn by the number of bytes written. */
  213. {
  214.   ulg a = 0L;           /* attributes returned by filetime() */
  215.   char *b;              /* malloc'ed file buffer */
  216.   extent k = 0;         /* result of zread */
  217.   int l = 0;            /* true if this file is a symbolic link */
  218.   int m;                /* method for this entry */
  219.   ulg o, p;             /* offsets in zip file */
  220.   long q = -3L;         /* size returned by filetime */
  221.   int r;                /* temporary variable */
  222.   ulg s = 0L;           /* size of compressed data */
  223.   int isdir;            /* set for a directory name */
  224.   int set_type = 0;     /* set if file type (ascii/binary) unknown */
  225.  
  226.   z->nam = strlen(z->zname);
  227.   isdir = z->zname[z->nam-1] == '/';
  228.   z->att = (ush)UNKNOWN; /* will be changed later */
  229.  
  230.   if ((z->tim = filetime(z->name, &a, &q)) == 0 || q < -2L)
  231.     return ZE_OPEN;
  232.   /* q is set to -1 if the input file is a device, -2 for a volume label */
  233.   if (q == -2L) {
  234.      isdir = 1;
  235.      q = 0;
  236.   }
  237.   remain = -1L; /* changed only for BIG_MEM */
  238.   window_size = 0L;
  239.  
  240.   /* Select method based on the suffix and the global method */
  241.   m = special != NULL && suffixes(z->name, special) ? STORE : method;
  242.  
  243.   /* Open file to zip up unless it is stdin */
  244.   if (strcmp(z->name, "-") == 0)
  245.   {
  246.     ifile = (ftype)zstdin;
  247. #if defined(MSDOS) || defined(__human68k__)
  248.     setmode(zstdin, O_BINARY);
  249. #endif
  250.   }
  251.   else
  252.   {
  253.     set_extra_field(z); /* create extra field and change z->att if desired */
  254.     l = issymlnk(a);
  255.     if (l)
  256.       ifile = fbad;
  257.     else if (isdir) { /* directory */
  258.       ifile = fbad;
  259.       m = STORE;
  260.       q = 0;
  261.     }
  262.     else if ((ifile = zopen(z->name, fhow)) == fbad)
  263.       return ZE_OPEN;
  264.  
  265. #ifdef MMAP
  266.     /* Map ordinary files but not devices. This code should go in fileio.c */
  267.     if (q > 0 && !translate_eol) {
  268.       if (window != NULL)
  269.         free(window);  /* window can't be a mapped file here */
  270.       window_size = q + MIN_LOOKAHEAD;
  271.       window = (uch*)mmap(0, window_size, PROT_READ, MAP_SHARED, ifile, 0);
  272.       if (window == (uch*)(-1)) {
  273.         window = NULL;
  274.         return ZE_OPEN;
  275.       }
  276.       /* If we can't touch the page beyond the end of file, remap
  277.        * using a garbage page:
  278.        */
  279.       remain = window_size & (PAGESIZE-1);
  280.       if (remain > 0 && remain <= MIN_LOOKAHEAD &&
  281.         mmap(window+window_size-remain, MIN_LOOKAHEAD, PROT_READ,
  282.              MAP_SHARED | MAP_FIXED, ifile, 0) == (char*)(-1)) {
  283.         /* The input file has at least MIN_LOOKAHEAD bytes, otherwise
  284.          * we would have enough space in the first page (assuming a page
  285.          * size of at least 512 bytes)
  286.          */
  287.         fprintf(mesg, " cannot extend mmap on %s", z->name);
  288.         window = NULL;
  289.         return ZE_OPEN;
  290.       }
  291.       remain = q;
  292.     }
  293. #else
  294. # ifdef BIG_MEM
  295.     /* Read the whole input file at once */
  296.     if (q > 0 && !translate_eol) {
  297.       window_size = q + MIN_LOOKAHEAD;
  298.       window = window ? (uch*) realloc(window, (unsigned)window_size)
  299.                       : (uch*) malloc((unsigned)window_size);
  300.       /* Just use normal code if big malloc or realloc fails: */
  301.       if (window != NULL) {
  302.         remain = zread(ifile, (char*)window, q+1);
  303.         if (remain != q) {
  304.           fprintf(mesg, " q=%ld, remain=%ld ", q, remain);
  305.           error("can't read whole file at once");
  306.         }
  307.       } else {
  308.         window_size = 0L;
  309.       }
  310.     }
  311. # endif /* BIG_MEM */
  312. #endif /* MMAP */
  313.  
  314.   } /* strcmp(z->name, "-") == 0 */
  315.  
  316.   if (l || q == 0)
  317.     m = STORE;
  318.   if (m == BEST)
  319.     m = DEFLATE;
  320.  
  321.   /* Do not create STORED files with extended local headers if the
  322.    * input size is not known, because such files could not be extracted.
  323.    * So if the zip file is not seekable and the input file is not
  324.    * on disk, obey the -0 option by forcing deflation with stored block.
  325.    * Note however that using "zip -0" as filter is not very useful...
  326.    * ??? to be done.
  327.    */
  328.  
  329.   /* Fill in header information and write local header to zip file.
  330.    * This header will later be re-written since compressed length and
  331.    * crc are not yet known.
  332.    */
  333.  
  334.   /* (Assume ext, cext, com, and zname already filled in.) */
  335. #if defined(OS2) || defined(WIN32)
  336.   z->vem = z->dosflag ? 20       /* Made under MSDOS by PKZIP 2.0 */
  337.          : OS_CODE + REVISION;
  338.   /* For a FAT file system, we cheat and pretend that the file
  339.    * was not made on OS2 but under DOS. unzip is confused otherwise.
  340.    */
  341. #else
  342.   z->vem = dosify ? 20 : OS_CODE + REVISION;
  343. #endif
  344.  
  345.   z->ver = m == STORE ? 10 : 20;     /* Need PKUNZIP 2.0 except for store */
  346.   z->crc = 0;  /* to be updated later */
  347.   /* Assume first that we will need an extended local header: */
  348.   z->flg = 8;  /* to be updated later */
  349. #ifdef CRYPT
  350.   if (key != NULL) {
  351.     z->flg |= 1;
  352.     /* Since we do not yet know the crc here, we pretend that the crc
  353.      * is the modification time:
  354.      */
  355.     z->crc = z->tim << 16;
  356.   }
  357. #endif
  358.   z->lflg = z->flg;
  359.   z->how = m;                             /* may be changed later  */
  360.   z->siz = m == STORE && q >= 0 ? q : 0;  /* will be changed later  */
  361.   z->len = q >= 0 ? q : 0;                /* may be changed later  */
  362.   z->dsk = 0;
  363.   if (z->att == (ush)UNKNOWN) {
  364.       z->att = BINARY;                    /* set sensible value in header */
  365.       set_type = 1;
  366.   }
  367.   z->atx = z->dosflag ? a & 0xff : a;     /* Attributes from filetime() */
  368.   z->off = tempzn;
  369.   if ((r = putlocal(z, y)) != ZE_OK)
  370.     return r;
  371.   tempzn += 4 + LOCHEAD + z->nam + z->ext;
  372.  
  373. #ifdef CRYPT
  374.   if (key != NULL) {
  375.     crypthead(key, z->crc, y);
  376.     z->siz += RAND_HEAD_LEN;  /* to be updated later */
  377.     tempzn += RAND_HEAD_LEN;
  378.   }
  379. #endif
  380.   if (ferror(y))
  381.     err(ZE_WRITE, "unexpected error on zip file");
  382.   o = ftell(y); /* for debugging only, ftell can fail on pipes */
  383.   if (ferror(y))
  384.     clearerr(y); 
  385.  
  386.   /* Write stored or deflated file to zip file */
  387.   isize = 0L;
  388.   crc = updcrc((char *)NULL, 0);
  389.  
  390.   if (m == DEFLATE) {
  391.      bi_init(y);
  392.      if (set_type) z->att = (ush)UNKNOWN; /* will be changed in deflate() */
  393.      ct_init(&z->att, &m);
  394.      lm_init(level, &z->flg);
  395.      s = deflate();
  396.   }
  397.   else
  398.   {
  399.     if ((b = malloc(CBSZ)) == NULL)
  400.        return ZE_MEM;
  401.  
  402.     if (!isdir) /* no read for directories */
  403.     while ((k = l ? rdsymlnk(z->name, b, CBSZ) : file_read(b, CBSZ)) > 0)
  404.     {
  405.       if (zfwrite(b, 1, k, y) != k)
  406.       {
  407.         free((voidp *)b);
  408.         return ZE_TEMP;
  409.       }
  410.       if (verbose) putc('.', stderr);
  411. #ifdef MINIX
  412.       if (l)
  413.         q = k;
  414. #endif /* MINIX */
  415.       if (l)
  416.         break;
  417.     }
  418.     free((voidp *)b);
  419.     s = isize;
  420.   }
  421.   if (ifile != fbad && zerr(ifile))
  422.     return ZE_READ;
  423.   if (ifile != fbad)
  424.     zclose(ifile);
  425. #ifdef MMAP
  426.   if (remain >= 0L) {
  427.     munmap(window, window_size);
  428.     window = NULL;
  429.   }
  430. #endif
  431.  
  432.   tempzn += s;
  433.   p = tempzn; /* save for future fseek() */
  434.  
  435. #if (!defined(MSDOS) || defined(OS2)) && !defined(VMS)
  436.   /* Check input size (but not in VMS -- variable record lengths mess it up)
  437.    * and not on MSDOS -- diet in TSR mode reports an incorrect file size)
  438.    */
  439.   if (q >= 0 && isize != (ulg)q && !translate_eol)
  440.   {
  441.     Trace((mesg, " i=%ld, q=%ld ", isize, q));
  442.     warn(" file size changed while zipping ", z->name);
  443.   }
  444. #endif
  445.  
  446.   /* Try to rewrite the local header with correct information */
  447.   z->crc = crc;
  448.   z->siz = s;
  449. #ifdef CRYPT
  450.   if (key != NULL)
  451.     z->siz += RAND_HEAD_LEN;
  452. #endif
  453.   z->len = isize;
  454.   if (fseek(y, z->off, SEEK_SET)) {
  455.     if (z->how != (ush) m)
  456.        error("can't rewrite method");
  457.     if (m == STORE && q < 0)
  458.        err(ZE_PARMS, "zip -0 not supported for I/O on pipes or devices");
  459.     if ((r = putextended(z, y)) != ZE_OK)
  460.       return r;
  461.     tempzn += 16L;
  462.     z->flg = z->lflg; /* if flg modified by inflate */
  463.   } else {
  464.      /* seek ok, ftell() should work, check compressed size */
  465. #ifndef VMS
  466.     if (p - o != s) {
  467.       fprintf(mesg, " s=%ld, actual=%ld ", s, p-o);
  468.       error("incorrect compressed size");
  469.     }
  470. #endif
  471.     z->how = m;
  472.     z->ver = m == STORE ? 10 : 20;     /* Need PKUNZIP 2.0 except for store */
  473.     if ((z->flg & 1) == 0)
  474.       z->flg &= ~8; /* clear the extended local header flag */
  475.     z->lflg = z->flg;
  476.     /* rewrite the local header: */
  477.     if ((r = putlocal(z, y)) != ZE_OK)
  478.       return r;
  479.     if (fseek(y, p, SEEK_SET))
  480.       return ZE_READ;
  481.     if ((z->flg & 1) != 0) {
  482.       /* encrypted file, extended header still required */
  483.       if ((r = putextended(z, y)) != ZE_OK)
  484.         return r;
  485.       tempzn += 16L;
  486.     }
  487.   }
  488.   /* Free the local extra field which is no longer needed */
  489.   if (z->ext) {
  490.     if (z->extra != z->cextra)
  491.       free((voidp *)(z->extra));
  492.     z->ext = 0;
  493.   }
  494.  
  495.   /* Display statistics */
  496.   if (noisy)
  497.   {
  498.     if (verbose)
  499.       fprintf(mesg, "\t(in=%lu) (out=%lu)", isize, s);
  500.     if (m == DEFLATE)
  501.       fprintf(mesg, " (deflated %d%%)\n", percent(isize, s));
  502.     else
  503.       fprintf(mesg, " (stored 0%%)\n");
  504.     fflush(mesg);
  505.   }
  506.   return ZE_OK;
  507. }
  508.  
  509.  
  510. int file_read(buf, size)
  511.   char *buf;
  512.   unsigned size;
  513. /* Read a new buffer from the current input file, perform end-of-line
  514.  * translation, and update the crc and input file size.
  515.  * IN assertion: size >= 2 (for end-of-line translation)
  516.  */
  517. {
  518.   unsigned len;
  519.   char far *b;
  520.  
  521. #if defined(MMAP) || defined(BIG_MEM)
  522.   if (remain == 0L) {
  523.     return 0;
  524.   } else if (remain > 0L) {
  525.     /* The window data is already in place. We still compute the crc
  526.      * by 32K blocks instead of once on whole file to keep a certain
  527.      * locality of reference.
  528.      */
  529.     Assert (buf == (char*)window + isize, "are you lost?");
  530.     if (size > remain) size = remain;
  531.     if (size > WSIZE) size = WSIZE; /* don't touch all pages at once */
  532.     remain -= (long) size;
  533.     len = size;
  534.   } else
  535. #endif
  536.   if (translate_eol == 0) {
  537.     len = zread(ifile, buf, size);
  538.     if (len == (unsigned)EOF || len == 0) return (int)len;
  539.  
  540.   } else if (translate_eol == 1) {
  541.     /* Transform LF to CR LF */
  542.     size >>= 1;
  543.     b = buf+size;
  544.     size = len = zread(ifile, b, size);
  545.     if (len == (unsigned)EOF || len == 0) return (int)len;
  546.     do {
  547.        if ((*buf++ = *b++) == '\n') *(buf-1) = '\r', *buf++ = '\n', len++;
  548.     } while (--size != 0);
  549.     buf -= len;
  550.  
  551.   } else {
  552.     /* Transform CR LF to LF and suppress final ^Z */
  553.     b = buf;
  554.     size = len = zread(ifile, buf, size-1);
  555.     if (len == (unsigned)EOF || len == 0) return (int)len;
  556.     buf[len] = '\n'; /* I should check if next char is really a \n */
  557.     do {
  558.        if ((*buf++ = *b++) == '\r' && *b == '\n') buf--, len--;
  559.     } while (--size != 0);
  560.     if (len == 0) {
  561.        zread(ifile, buf, 1); len = 1; /* keep single \r if EOF */
  562.     } else {
  563.        buf -= len;
  564.        if (buf[len-1] == ('Z' & 0x1f)) len--; /* suppress final ^Z */
  565.     }
  566.   }
  567.   crc = updcrc(buf, len);
  568.   isize += (ulg)len;
  569.   return (int)len;
  570. }
  571. #endif /* !UTIL */
  572.